package com.hsu.apibackend.controller;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hsu.apibackend.common.BaseResponse;
import com.hsu.apibackend.common.ErrorCode;
import com.hsu.apibackend.common.ResultUtils;
import com.hsu.apibackend.exception.BusinessException;
import com.hsu.apibackend.model.dto.pay.PayCreateRequest;
import com.hsu.apibackend.model.dto.productorder.ProductOrderQueryRequest;
import com.hsu.apibackend.model.entity.ProductInfo;
import com.hsu.apibackend.model.entity.ProductOrder;
import com.hsu.apibackend.model.enums.PaymentStatusEnum;
import com.hsu.apibackend.model.vo.OrderVO;
import com.hsu.apibackend.model.vo.ProductOrderVO;
import com.hsu.apibackend.model.vo.UserVO;
import com.hsu.apibackend.service.OrderService;
import com.hsu.apibackend.service.ProductOrderService;
import com.hsu.apibackend.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.hsu.apibackend.constant.PayConstant.QUERY_ORDER_STATUS;
import static com.hsu.apibackend.model.enums.PaymentStatusEnum.SUCCESS;

@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {

    @Resource
    private OrderService orderService;

    @Resource
    private ProductOrderService productOrderService;

    @Resource
    private UserService userService;

    @Resource
    private RedisTemplate<String, Boolean> redisTemplate;

    // region 增删改查

    /**
     * 取消订单
     *
     * @param orderNo 订单号
     * @return {@link BaseResponse}<{@link Boolean}> 返回是否取消成功
     */
    @PostMapping("/closed")
    public BaseResponse<Boolean> closedProductOrder(String orderNo) {
        // 校验订单号是否为空
        if (StringUtils.isBlank(orderNo)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 判断订单是否存在
        ProductOrder productOrder = productOrderService.getProductOrderByOutTradeNo(orderNo);
        if (productOrder == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }

        // 根据支付类型获取对应的订单服务
        ProductOrderService orderServiceByPayType = orderService.getProductOrderServiceByPayType(productOrder.getPayType());

        // 更新订单状态为已取消
        boolean closedResult = orderServiceByPayType.updateOrderStatusByOrderNo(orderNo, PaymentStatusEnum.CLOSED.getValue());

        return ResultUtils.success(closedResult); // 返回取消结果
    }

    /**
     * 删除订单
     *
     * @param id 订单ID
     * @param request 请求对象，用于获取当前登录的用户信息
     * @return {@link BaseResponse}<{@link Boolean}> 返回删除结果
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteProductOrder(String id, HttpServletRequest request) {
        // 校验订单ID是否为空
        if (StringUtils.isBlank(id)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 获取当前登录的用户信息
        UserVO loginUser = userService.getLoginUser(request);

        // 校验订单是否存在
        ProductOrder productOrder = productOrderService.getById(id);
        if (productOrder == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }

        // 仅订单的创建者或管理员有权限删除订单
        if (!productOrder.getUserId().equals(loginUser.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }

        // 删除订单
        return ResultUtils.success(productOrderService.removeById(id));
    }

    /**
     * 按id获取产品订单
     *
     * @param id id
     * @return {@link BaseResponse}<{@link ProductOrderVO}>
     */
    @GetMapping("/get")
    public BaseResponse<ProductOrderVO> getProductOrderById(String id) {
        if (StringUtils.isBlank(id)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        ProductOrder productOrder = productOrderService.getById(id);
        if (productOrder == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        ProductOrderVO productOrderVO = formatProductOrderVO(productOrder);
        return ResultUtils.success(productOrderVO);
    }

    /**
     * 分页获取产品订单列表
     *
     * @param productOrderQueryRequest 产品订单查询请求
     * @param request                  请求对象
     * @return {@link BaseResponse}<{@link OrderVO}> 返回分页后的订单列表
     */
    @GetMapping("/list/page")
    public BaseResponse<OrderVO> listProductOrderByPage(ProductOrderQueryRequest productOrderQueryRequest, HttpServletRequest request) {
        if (productOrderQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 创建订单查询对象并复制查询参数
        ProductOrder productOrder = new ProductOrder();
        BeanUtils.copyProperties(productOrderQueryRequest, productOrder);

        long size = productOrderQueryRequest.getPageSize();
        String orderName = productOrderQueryRequest.getOrderName();
        String orderNo = productOrderQueryRequest.getOrderNo();
        Integer total = productOrderQueryRequest.getTotal();
        String status = productOrderQueryRequest.getStatus();
        String productInfo = productOrderQueryRequest.getProductInfo();
        String payType = productOrderQueryRequest.getPayType();
        Integer addPoints = productOrderQueryRequest.getAddPoints();
        long current = productOrderQueryRequest.getCurrent();

        // 限制页面大小，防止恶意抓取
        if (size > 50) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 获取当前登录的用户信息
        UserVO loginUser = userService.getLoginUser(request);
        Long userId = loginUser.getId();

        // 构建查询条件
        QueryWrapper<ProductOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(orderName), "orderName", orderName)
                .like(StringUtils.isNotBlank(productInfo), "productInfo", productInfo)
                .eq("userId", userId)
                .eq(StringUtils.isNotBlank(orderNo), "orderNo", orderNo)
                .eq(StringUtils.isNotBlank(status), "status", status)
                .eq(StringUtils.isNotBlank(payType), "payType", payType)
                .eq(ObjectUtils.isNotEmpty(addPoints), "addPoints", addPoints)
                .eq(ObjectUtils.isNotEmpty(total), "total", total);

        // 将未支付的订单放在前面
        queryWrapper.last("ORDER BY CASE WHEN status = 'NOTPAY' THEN 0 ELSE 1 END, status");

        // 分页查询
        Page<ProductOrder> productOrderPage = productOrderService.page(new Page<>(current, size), queryWrapper);

        // 创建返回的订单VO
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(productOrderPage, orderVO);

        // 处理订单信息并将其转换为VO格式
        List<ProductOrderVO> productOrders = productOrderPage.getRecords().stream()
                .map(this::formatProductOrderVO)
                .collect(Collectors.toList());

        orderVO.setRecords(productOrders);

        return ResultUtils.success(orderVO);
    }

    // endregion

    /**
     * 创建订单
     *
     * @param request          请求对象，用于获取当前用户信息
     * @param payCreateRequest 付款创建请求，包含产品ID和支付类型
     * @return {@link BaseResponse}<{@link ProductOrderVO}> 返回创建的订单信息
     */
    @PostMapping("/create")
    public BaseResponse<ProductOrderVO> createOrder(@RequestBody PayCreateRequest payCreateRequest, HttpServletRequest request) {
        // 校验请求参数是否合法
        if (ObjectUtils.anyNull(payCreateRequest) || StringUtils.isBlank(payCreateRequest.getProductId())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Long productId = Long.valueOf(payCreateRequest.getProductId());
        String payType = payCreateRequest.getPayType();

        // 校验支付方式是否合法
        if (StringUtils.isBlank(payType)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "暂无该支付方式");
        }

        // 获取当前登录用户
        UserVO loginUser = userService.getLoginUser(request);

        // 根据支付类型和产品ID创建订单
        ProductOrderVO productOrderVO = orderService.createOrderByPayType(productId, payType, loginUser);

        // 如果订单创建失败，抛出异常
        if (productOrderVO == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "订单创建失败，请稍后再试");
        }

        // 返回创建的订单信息
        return ResultUtils.success(productOrderVO);
    }

    /**
     * 查询订单状态
     *
     * @param productOrderQueryRequest 订单状态查询请求，包含订单号
     * @return {@link BaseResponse}<{@link Boolean}> 返回订单是否成功支付的状态
     */
    @PostMapping("/query/status")
    public BaseResponse<Boolean> queryOrderStatus(@RequestBody ProductOrderQueryRequest productOrderQueryRequest) {
        // 校验请求参数是否有效
        if (ObjectUtils.isEmpty(productOrderQueryRequest) || StringUtils.isBlank(productOrderQueryRequest.getOrderNo())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        String orderNo = productOrderQueryRequest.getOrderNo();

        // 从Redis中获取订单状态缓存
        Boolean data = redisTemplate.opsForValue().get(QUERY_ORDER_STATUS + orderNo);

        // 如果Redis中缓存了订单状态且为false，直接返回false
        if (Boolean.FALSE.equals(data)) {
            return ResultUtils.success(data);
        }

        // 根据订单号查询订单信息
        ProductOrder productOrder = productOrderService.getProductOrderByOutTradeNo(orderNo);

        // 如果订单状态为支付成功，返回true
        if (SUCCESS.getValue().equals(productOrder.getStatus())) {
            return ResultUtils.success(true);
        }

        // 如果订单未支付成功，将状态缓存到Redis并设置过期时间为5分钟
        redisTemplate.opsForValue().set(QUERY_ORDER_STATUS + orderNo, false, 5, TimeUnit.MINUTES);

        return ResultUtils.success(false);
    }

    /**
     * 解析订单通知结果
     * 通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m
     *
     * @param notifyData 通知数据，包含支付平台发送的订单状态通知信息
     * @param request    请求对象，用于获取上下文信息
     * @return {@link String} 返回订单通知处理结果
     */
    @PostMapping("/notify/order")
    public String parseOrderNotifyResult(@RequestBody String notifyData, HttpServletRequest request) {
        // 调用订单服务处理通知数据
        return orderService.doOrderNotify(notifyData, request);
    }

    /**
     * 格式化产品订单对象
     *
     * @param productOrder 产品订单实体
     * @return {@link ProductOrderVO} 格式化后的产品订单视图对象
     */
    private ProductOrderVO formatProductOrderVO(ProductOrder productOrder) {
        // 创建一个新的 ProductOrderVO 对象
        ProductOrderVO productOrderVO = new ProductOrderVO();

        // 将 productOrder 的属性拷贝到 productOrderVO 中
        BeanUtils.copyProperties(productOrder, productOrderVO);

        // 将产品信息字符串解析为 ProductInfo 对象
        ProductInfo prodInfo = JSONUtil.toBean(productOrder.getProductInfo(), ProductInfo.class);

        // 设置描述和产品类型
        productOrderVO.setDescription(prodInfo.getDescription());
        productOrderVO.setProductType(prodInfo.getProductType());

        // 将总金额从分转换为元，并保留两位小数
        String voTotal = String.valueOf(prodInfo.getTotal());
        BigDecimal total = new BigDecimal(voTotal).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);

        // 设置总金额
        productOrderVO.setTotal(total.toString());

        return productOrderVO;
    }

}
